#include "kernel/smp/cpu.h"
#include "libs/lib.h"
#include "kernel/log/log.h"
#include "libs/msr.h"
#include "libs/types.h"



Cpu::Cpu(/* args */)
{
}

Cpu::~Cpu()
{
}


cpumanager* cpumanager::cpum = 0;

cpumanager::cpumanager(/* args */)
{

    
	uint32_t a,b,c,d;
	unsigned int CpuFacName[4] = {0,0,0,0};
	char	FactoryName[17] = {0};


	cpus[0] = new Cpu();

	//vendor_string
	get_cpuid(0,0,&CpuFacName[0],&CpuFacName[1],&CpuFacName[2],&CpuFacName[3]);

	*(unsigned int*)&FactoryName[0] = CpuFacName[1];

	*(unsigned int*)&FactoryName[4] = CpuFacName[3];

	*(unsigned int*)&FactoryName[8] = CpuFacName[2];	

	FactoryName[12] = '\0';
	LOG_INFO("%s\t%#010x\t%#010x\t%#010x\n",FactoryName,CpuFacName[1],CpuFacName[3],CpuFacName[2]);
	
	//brand_string
	for(uint64_t i = 0x80000002;i < 0x80000005;i++)
	{
		get_cpuid(i,0,&CpuFacName[0],&CpuFacName[1],&CpuFacName[2],&CpuFacName[3]);

		*(unsigned int*)&FactoryName[0] = CpuFacName[0];

		*(unsigned int*)&FactoryName[4] = CpuFacName[1];

		*(unsigned int*)&FactoryName[8] = CpuFacName[2];

		*(unsigned int*)&FactoryName[12] = CpuFacName[3];

		FactoryName[16] = '\0';
		LOG_INFO("%s",FactoryName);
	}
	LOG_INFO("\n");

	//Version Informatin Type,Family,Model,and Stepping ID
	get_cpuid(1,0,&CpuFacName[0],&CpuFacName[1],&CpuFacName[2],&CpuFacName[3]);
	// LOG_INFO("Family Code:%#010x,Extended Family:%#010x,Model Number:%#010x,Extended Model:%#010x,Processor Type:%#010x,Stepping ID:%#010x\n",(CpuFacName[0] >> 8 & 0xf),(CpuFacName[0] >> 20 & 0xff),(CpuFacName[0] >> 4 & 0xf),(CpuFacName[0] >> 16 & 0xf),(CpuFacName[0] >> 12 & 0x3),(CpuFacName[0] & 0xf));

	//get Linear/Physical Address size
	get_cpuid(0x80000008,0,&CpuFacName[0],&CpuFacName[1],&CpuFacName[2],&CpuFacName[3]);
	// LOG_INFO("Physical Address size:%08d,Linear Address size:%08d\n",(CpuFacName[0] & 0xff),(CpuFacName[0] >> 8 & 0xff));

	//max cpuid operation code
	get_cpuid(0,0,&CpuFacName[0],&CpuFacName[1],&CpuFacName[2],&CpuFacName[3]);
	// LOG_INFO("MAX Basic Operation Code :%#010x\t",CpuFacName[0]);

	get_cpuid(0x80000000,0,&CpuFacName[0],&CpuFacName[1],&CpuFacName[2],&CpuFacName[3]);
	// LOG_INFO("MAX Extended Operation Code :%#010x\n",CpuFacName[0]);
    
	
	cpufunction.apicSupport = hd_detect(1,0,3,9);
	cpufunction.x2apicSupport = hd_detect(1,0,2,21);


	uint8_t i = 0;
	for (uint64_t i = 0;; i++)
	{
		get_cpuid(0xb,i,&a,&b,&c,&d);

		if(i == 0){
			smtIdWidth = a & 0x1f;
			numOfCpus = b & 0xff;
		}	
		if(i == 1){
			coreIdWidth = a & 0x1f;
		}
		if(i == 2){
			packetWidth = 32 - smtIdWidth - coreIdWidth;
		}


		if((c >> 8  & 0xff) == 0)
			break;
	}
	

	cpum = this;
}

cpumanager::~cpumanager()
{
}
